package com.ra.landlord;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.googlecode.cswish.annotation.Rest;
import com.googlecode.cswish.oosearch.Condition;
import com.googlecode.cswish.oosearch.QLInfo;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.util.bean.ModelUtil;
import com.ra.landlord.constant.FeeRuleCalcMode;
import com.ra.landlord.constant.FeeRuleType;
import com.ra.landlord.constant.LandlordConstant;
import com.ra.order.rental.RentalOrder;
import com.ra.order.rental.RentalOrderService;
import com.ra.util.DateTimeUtil;
import com.ra.util.PrinterService;

/**
 * 费用服务（新）
 * @author colin
 * @date 2015年7月1日
 */
@Service
public class FeeRecordService {
	
	private static final Log logger = LogFactory.getLog(FeeRecordService.class);

	@Resource
	private GenericService genericService;
	
	@Resource
	private FeeAdditionService feeAdditionService;
	
	@Resource
	private LandlordUserService landlordUserService;
	
	@Resource
	private PrinterService printerService;
	
	@Resource
	private RentalOrderService rentalOrderService;

	@Resource
	private FeeService feeService;
	
	@PersistenceContext(unitName="espirit")
	protected EntityManager em;
	
	/**
	 * 创建费用记录
	 * @param model
	 * @return
	 */
	@Transactional
	@Rest(type="add")
	public FeeRecord addFeeRecord(FeeRecord model) {
		LandlordUser landlordUser = landlordUserService.getLoginUser();
		model.setLandlordUser(landlordUser.getOwnerUser());
		model.setAgent(landlordUser);
		return genericService.add(model);
	}
	
	/**
	 * 删除费用，逻辑删除
	 * @param model
	 * @return
	 */
	@Rest(type="delete")
	public FeeRecord deleteFeeRecord(FeeRecord model) {
		FeeRecord fee = genericService.load(model);
		fee.setStatus(0);
		fee = genericService.merge(fee);
		return fee;
	}
	
	
	@Rest(type="delete")
	public boolean deleteFeeRecordByRoom(Room room) {
		boolean result = false;
		FeeRecord feeRecordModel = new FeeRecord();
		feeRecordModel.setRoom(room);
		feeRecordModel.setStatus(FeeRecord.FEE_STATUS_RENT_TODO);
		
		List<FeeRecord> feeRecords = genericService.searchAll(feeRecordModel).getData();
		
		if (feeRecords != null && feeRecords.size() > 0) {
			for (FeeRecord feeRecord : feeRecords) {
				//根据feeRecord查对应的rentalOrder
				RentalOrder rentalOrder = rentalOrderService.searchRentalOrderByFeeRecord(feeRecord);
				if (rentalOrder == null) {
					//如果没有生成订单，则将feeRecord删除
					result = genericService.delete(feeRecord);
					logger.debug("delete feeRecord by room successful. room.id="+room.getId());
				}
			}
		}
		
		return result;
	}
	/**
	 * 修复费用
	 * @param model
	 * @return
	 */
	@Rest(type="delete")
	@Transactional
	public boolean repairedFeeRecordByRoom(Room room) {
		room = em.find(Room.class, room.getId());
		em.refresh(room);
		boolean result = false;
		FeeRecord feeRecordModel = new FeeRecord();
		feeRecordModel.setRoom(room);
		feeRecordModel.setStatus(FeeRecord.FEE_STATUS_RENT_TODO);
		
		List<FeeRecord> feeRecords = genericService.searchAll(feeRecordModel).getData();
		FeeRecord feeRecord = feeService.getOrGenerateFeeRecordIfNotExists(room.getAgreement());
		RentalOrder rentalOrder = rentalOrderService.searchRentalOrderByFeeRecord(feeRecord);
		if (feeRecord != null && (rentalOrder == null || rentalOrder.getOrderState() == RentalOrder.ORDER_STATE_WAITING_PAYMENT)) {
			//没有生成收租单，将所有收费项更新到跟room最新状态；已经生成收租单，费用配置被移除后，收费项应该保留，新增的费用配置产生未确认的收费项。
			List<FeeAdditionRecord> feeAdditionRecords = feeRecord.getFeeAdditionRecords();
			BigDecimal price = new BigDecimal(0);
			List<FeeAdditionRecord> removeList = new ArrayList<FeeAdditionRecord>(5);
			if (feeAdditionRecords != null) {
				for (FeeAdditionRecord feeAdditionRecord : feeAdditionRecords) {
					FeeRuleCfg feeRuleCfg = feeAdditionRecord.getFeeRuleCfg();
					if (feeRuleCfg != null && feeRuleCfg.getId() != 0 && feeRuleCfg.getFeeRuleCfgDesc().getType() == FeeRuleType.fixed ) {
						if (rentalOrder == null || FeeAdditionRecord.STATUS_NEED_CONFIRM.equals(feeAdditionRecord.getStatus())) {
							//price = price.subtract(feeRuleCfg.getFeeRuleCfgCalc().getPrice());
							price = price.subtract(feeAdditionRecord.getPriceRecv());
							removeList.add(feeAdditionRecord);
						}
					}
				}
				feeAdditionRecords.removeAll(removeList);
			}
			
			List<FeeRule> feeRules = room.getFeeRules();
			if (feeRules != null) {
				Meter fixedMeter = genericService.load(Meter.class, 2);
				for (FeeRule feeRule : feeRules) {
					FeeRuleCfg feeRuleCfg = feeRule.getFeeRuleCfg();
					if (feeRuleCfg != null && feeRuleCfg.getId() != 0 && feeRuleCfg.getFeeRuleCfgDesc().getType() == FeeRuleType.fixed ) {
						boolean needGenerateFeeAdditionRecord = true;
						for (FeeAdditionRecord feeAdditionRecord: feeAdditionRecords) {
							if (feeAdditionRecord.getFeeRuleCfg().getId().equals(feeRuleCfg.getId())) {
								needGenerateFeeAdditionRecord = false;
								break;
							}
						}
						if (!needGenerateFeeAdditionRecord) {
							continue ;
						}
						
						int monthDist = feeRecord.getAgreement().getRentCycle() + 1;
						if (feeRecord.getAgreement().getFees() == null || feeRecord.getAgreement().getFees().size() <= 1) {
							monthDist = feeRecord.getAgreement().getPayNum();
						}
						FeeRuleCfgCalc feeRuleCfgCalc = feeRuleCfg.getFeeRuleCfgCalc();
						
						FeeAdditionRecord feeAdditionRecord = new FeeAdditionRecord();
						feeAdditionRecord.setFeeRuleCfg(feeRule.getFeeRuleCfg());

						if (feeRuleCfg.getFeeRuleCfgDesc().getCalcMode() == FeeRuleCalcMode.areaFactor) {
							feeAdditionRecord.setPriceRecv(room.getArea().multiply(feeRuleCfgCalc.getPrice()));
						} else {
							feeAdditionRecord.setPriceRecv(feeRuleCfgCalc.getPrice());
						}
						feeAdditionRecord.setPriceRecv(feeAdditionRecord.getPriceRecv().multiply(BigDecimal.valueOf(monthDist)).setScale(2, RoundingMode.HALF_UP));
						price = price.add(feeAdditionRecord.getPriceRecv());
						
						feeAdditionRecord.setMeter1(fixedMeter);
						feeAdditionRecord.setMeter2(fixedMeter);
						feeAdditionRecord.setFeeRecord(feeRecord);
						if (rentalOrder == null) {
							feeAdditionRecord.setStatus(FeeAdditionRecord.STATUS_CONFIRMED);
						} else {
							feeAdditionRecord.setStatus(FeeAdditionRecord.STATUS_NEED_CONFIRM);
						}
						//genericService.add(feeAdditionRecord);
						feeAdditionRecords.add(feeAdditionRecord);
						
					}
				}
			}
			feeRecord.setAmountRecv(feeRecord.getAmountRecv().add(price));
			genericService.merge(feeRecord);
			
			logger.info("repair feerecord by fix feerulecfg. room.id="+room.getId());
		}
		
		return result;
	}
	
	/**
	 * 根据费用信息查询对应订单
	 * @param fee
	 * @return 费用对应订单
	 */
	public RentalOrder searchRentalOrderByFee(FeeRecord feeRecord) {
		RentalOrder queryRentalOrder = new RentalOrder();
		queryRentalOrder.setFeeRecord(feeRecord);
		queryRentalOrder.setOrderType(RentalOrder.ORDERTYPE_RENTAL);
		RentalOrder RentalOrder = null;
		if(feeRecord != null) {
			//自从加了房租补贴订单后，后面应该考虑加个订单类型，这里应该只查租金订单
			RentalOrder = genericService.searchByModel(queryRentalOrder, Condition.SEARCH_ONE, false, true).getData(0);
		}
		return RentalOrder;
	}
	
	/**
	 * 确认收租
	 * @param model
	 * @return
	 */
	@Transactional
	@Rest(type="update")
	public FeeRecord updateFeeRecord(FeeRecord model) {
		//FeeRecord fee = null;
		LandlordUser landlordUser = model.getLandlordUser();
		if(landlordUser == null) {
			landlordUser = landlordUserService.getLoginUser();
		}
		
		//fee = new FeeRecord();
		model.setLandlordUser(landlordUser.getOwnerUser());
		model.setRoom(genericService.load(model.getRoom()));
		model.setAgreement(model.getRoom().getAgreement());
		if (model.getTenantUser() != null) {
			model.setTenantUser(model.getTenantUser());
		}
		
		model.setAgent(landlordUser);
		model.setDateActual(DateTimeUtil.DATETIME_FORMAT.format(Calendar.getInstance().getTime()));
		if (model.getAmountActual() != null) {
			model.setAmountActual(model.getAmountActual().setScale(2,BigDecimal.ROUND_HALF_UP));
		}
		model.setAmountRecv(model.getAmountRecv().setScale(2,BigDecimal.ROUND_HALF_UP));
		if (model.getBalance() != null) {
			model.setBalance(model.getBalance().setScale(2,BigDecimal.ROUND_HALF_UP));
		} else {
			model.setBalance(new BigDecimal("0.00"));
		}
		if (model.getRental() == null) {
			if (model.getRoom() != null) {
				if (StringUtils.isNotBlank(model.getRoom().getRental())) {
					model.setRental(new BigDecimal(model.getRoom().getRental()));
				}else{
					model.setRental(new BigDecimal(0));
				}
			}
		}
		model.setRental(model.getRental().setScale(2,BigDecimal.ROUND_HALF_UP));
		model.setDateBeginRecv(DateTimeUtil.completeDateTime(model.getDateBeginRecv()));
		model.setDateEndRecv(DateTimeUtil.completeDateTime(model.getDateEndRecv()));
		//默认为1
		model.setType(1);
		
		List<FeeAdditionRecord> lstNewAddition = model.getFeeAdditionRecords();
		if (lstNewAddition != null ) {
			for (FeeAdditionRecord feeAdditionRecord : lstNewAddition) {
				feeAdditionRecord.setFeeRecord(model);
				FeeRuleCfg feeRuleCfg = genericService.load(feeAdditionRecord.getFeeRuleCfg());
				feeAdditionRecord.setFeeRuleCfg(feeRuleCfg);
				if (feeRuleCfg.getFeeRuleCfgDesc().getType() == FeeRuleType.fixed) {
					Meter meter = new Meter();
					meter.setId(2);
					feeAdditionRecord.setMeter1(meter);
					feeAdditionRecord.setMeter2(meter);
				}else if(feeRuleCfg.getFeeRuleCfgDesc().getType() == FeeRuleType.meter){
					Meter meter1 = genericService.load(feeAdditionRecord.getMeter1());
					Meter meter2 = genericService.load(feeAdditionRecord.getMeter2());
					
					if(meter1 == null){
						if(meter2 == null){
							Meter meter = new Meter();
							meter.setId(0);
							meter1 = meter;
							meter2 = meter;
						}else{
							meter1 = meter2;
						}
					}
					feeAdditionRecord.setMeter1(meter1);
					feeAdditionRecord.setMeter2(meter2);
				}
				//feeAddition.setPriceActual(feeAddition.getPriceActual().setScale(2,BigDecimal.ROUND_HALF_UP));
				BigDecimal priveRecv = feeAdditionRecord.getPriceRecv();
				if (priveRecv == null) {
					priveRecv = new BigDecimal(0);
				}
				feeAdditionRecord.setPriceRecv(priveRecv.setScale(2,BigDecimal.ROUND_HALF_UP));
				feeAdditionRecord.setOverdueFine(false);
				feeAdditionRecord.setLandlordUser(landlordUser.getOwnerUser());
				feeAdditionRecord.setId(null);
			}
		}else{
			model.setFeeAdditionRecords(new ArrayList<FeeAdditionRecord>());
		}
		
		FeeRecord resultFee = genericService.merge(model);
		
		return resultFee;
	}
	
	/**
	 * 收租后修改FeeRecord,改为已收
	 * 
	 * @return
	 */
	@Rest(type = "update")
	public FeeRecord closeFeeRecord(FeeRecord model, Integer payMode){
		FeeRecord feeRecord = genericService.load(model);
		if (feeRecord != null) {
			feeRecord.setStatus(FeeRecord.FEE_STATUS_RENT_DONE);
			String time = DateTimeUtil.formatDate(Calendar.getInstance().getTime());
			feeRecord.setDateActual(time);
			feeRecord.setPayMode(payMode);
			feeRecord = genericService.merge(feeRecord);
		}
		return feeRecord;
	}
	
	/**
	 * 根据房间关闭FeeRecord,改为已收
	 * 
	 * @return
	 */
	@Rest(type = "update")
	public List<FeeRecord> finishFeeRecordAndOrderByRoom(Room room){
		List<FeeRecord> resultFeeRecord = new ArrayList<>();
		FeeRecord feeRecord = new FeeRecord();
		feeRecord.setRoom(room);
		feeRecord.setStatus(FeeRecord.FEE_STATUS_RENT_TODO);
		List<FeeRecord> feeRecords = genericService.searchAll(feeRecord).getData();
		if (feeRecords != null && feeRecords.size() > 0) {
			for (FeeRecord dbFeeRecord : feeRecords) {
				FeeRecord tempFeeRecord = closeFeeRecord(dbFeeRecord, FeeRecord.FEE_PAYMODEL_CASH);
				if (tempFeeRecord != null) {
					//关闭订单
					rentalOrderService.rentalOrderSuccess(tempFeeRecord);
					resultFeeRecord.add(tempFeeRecord);
				}
			}
		}
		return resultFeeRecord;
	}
	
	/**
	 * 根据房间关闭FeeRecord,改为已收
	 * 
	 * @return
	 */
	@Rest(type = "update")
	public List<FeeRecord> closeFeeRecordAndOrderByRoom(Room room){
		List<FeeRecord> resultFeeRecord = new ArrayList<>();
		FeeRecord feeRecord = new FeeRecord();
		feeRecord.setRoom(room);
		feeRecord.setStatus(FeeRecord.FEE_STATUS_RENT_TODO);
		List<FeeRecord> feeRecords = genericService.searchAll(feeRecord).getData();
		if (feeRecords != null && feeRecords.size() > 0) {
			for (FeeRecord dbFeeRecord : feeRecords) {
				FeeRecord tempFeeRecord = closeFeeRecord(dbFeeRecord, FeeRecord.FEE_PAYMODEL_CASH);
				if (tempFeeRecord != null) {
					//关闭订单
					RentalOrder rentalOrder = rentalOrderService.searchRentalOrderByFeeRecord(tempFeeRecord);
					if (rentalOrder != null) {
						rentalOrderService.updateOrderState(rentalOrder.getId(), RentalOrder.ORDER_STATE_CLOSED);
					}
					resultFeeRecord.add(tempFeeRecord);
				}
			}
		}
		return resultFeeRecord;
	}
	
	
	/**
	 * 收租后修改FeeRecord
	 * 
	 * @return
	 */
	@Rest(type = "update")
	public FeeRecord updateFeeRecordAfterRent(Fee resultFee){
		FeeRecord feeRecordModel = new FeeRecord();
		FeeRecord modelFeeRecord = new FeeRecord();
		modelFeeRecord.setRoom(resultFee.getRoom());
		modelFeeRecord.setStatus(FeeRecord.FEE_STATUS_RENT_TODO);
		List<FeeRecord> feeRecords = searchFeeRecord(modelFeeRecord);
		if (feeRecords != null && feeRecords.size() > 0) {
			feeRecordModel = feeRecords.get(0);
			//删除feeAdditionRecord
			//feeRecord.setFeeAdditionRecords(null);
			feeRecordModel.setDateBeginRecv(resultFee.getDateBeginRecv());
			feeRecordModel.setDateEndRecv(resultFee.getDateEndRecv());
			feeRecordModel.setAmountRecv(resultFee.getAmountRecv());
			feeRecordModel.setAmountActual(resultFee.getAmountActual());
			feeRecordModel.setBalance(resultFee.getBalance());
			feeRecordModel.setRemark(resultFee.getRemark());
			feeRecordModel.setPayMode(resultFee.getPayMode());
			feeRecordModel.setStatus(1);
			
			List<FeeAddition> feeAdditions = resultFee.getFeeAdditions();
			List<FeeAdditionRecord> feeAdditionRecords = feeRecordModel.getFeeAdditionRecords();
			Map<Integer,FeeAddition> feeAdditionMap = new HashMap<>();
			if (feeAdditions != null && feeAdditions.size() > 0) {
				for (FeeAddition feeAddition : feeAdditions) {
					feeAdditionMap.put(feeAddition.getFeeRuleCfg().getId(), feeAddition);
				}
			}
			List<FeeAdditionRecord> newFeeAdditionRecords = new ArrayList<>();
			if (feeAdditionRecords != null && feeAdditionRecords.size() > 0) {
				
				for (FeeAdditionRecord feeAdditionRecord : feeAdditionRecords) {
					Integer feeRuleCfgId = feeAdditionRecord.getFeeRuleCfg().getId();
					FeeAddition feeAddition = feeAdditionMap.get(feeRuleCfgId);
					if (feeAddition != null) {
						feeAdditionRecord.setPriceActual(feeAddition.getPriceActual());
						newFeeAdditionRecords.add(feeAdditionRecord);
					}
					
				}
			}
			List<FeeAdditionRecord> oldFeeAdditionRecords = feeRecordModel.getFeeAdditionRecords();
			if (oldFeeAdditionRecords != null) {
				oldFeeAdditionRecords.clear();
				oldFeeAdditionRecords.addAll(newFeeAdditionRecords);
			}
		}
		Integer tempId = feeRecordModel.getId();
		copyFee2FeeRecord(resultFee, feeRecordModel);
		feeRecordModel.setId(tempId);
		
		FeeRecord feeRecordDB = updateFeeRecord(feeRecordModel);
		//收租后，修改订单状态
		rentalOrderService.rentalOrderSuccess(feeRecordDB);
		//rentalOrderService.closeRentalOrder(feeRecordDB);
		
		return feeRecordDB;
	}
	
	
	/**
	 * 查询费用
	 * @return
	 */
	@Rest(type = "search")
	public List<FeeRecord> searchFeeRecord(FeeRecord model){
		return this.genericService.searchByModel(model, Condition.DEFAULT).getData();
	}
	
	
	/**
	 * 打印未收租的费用票据
	 * @param room
	 * @return
	 */
	
	@Rest(type = "print")
	public Fee showTempReceiptView(Room model){
		Fee resultFee = null;
		Room room = genericService.load(model);
		if (room != null) {
			List<Fee> fees = room.getFees();
			if (fees != null && fees.size() > 0) {
				Fee lastFee = fees.get(fees.size()-1);
				// 附加费
				resultFee = calculateNewFee(lastFee,room);
				resultFee.setRoom(lastFee.getRoom());
				resultFee.setTenantUser(lastFee.getTenantUser());
			}
		}
		return resultFee;
	}
	
	/**
	 * 计算单个房间的待收费用
	 * 
	 * @param room
	 * @return
	 */
	
	@Rest(type = "calculate")
	public Fee calculateFee(Room room) {
		
		Fee resultFee = null;
		//如果有未付的Fees，直接返回第一条fee记录
		List<Fee> unpayFees = room.getUnpayFees();
		List<Fee> fees = room.getFees();
		List<Fee> agreementFees = room.getAgreement().getFees();
		if (room.getRentState() == LandlordConstant.RENT_STATE_BOOK) {
			resultFee = new Fee();
			resultFee.setAmountRecv(room.getAgreement().getRentPay());
		}
		if (unpayFees != null && unpayFees.size() > 0) {
			//若是通过手动生成费用，或者出租生成费用（房租、押金），将会执行此段代码
			//是否需要设置未付费用的附加费（比如水费电费。。。）
			return unpayFees.get(0);
		}else if(agreementFees != null && agreementFees.size() == 1){
			//相当于只有一条押金费用
			//计算该合同内的第一个月的费用
			Fee lastFee = fees.get(fees.size()-1);
			resultFee = calculateNewFee(lastFee,room);
		}else if(agreementFees != null && agreementFees.size() > 1){
			
			Fee lastFee = agreementFees.get(0);
			// 附加费
			List<FeeAddition> feeAdditions = new ArrayList<FeeAddition>();
			Date date = DateTimeUtil.StrToDate(lastFee.getDateEndRecv());
			if (date == null || date.compareTo(new Date()) >= 0){
				FeeAddition feeAddition = new FeeAddition();
				feeAddition.setFee(lastFee);
				feeAdditions = feeAdditionService.searchFeeAddition(feeAddition);
				lastFee.setFeeAdditions(feeAdditions);
				resultFee = lastFee;
			}else{
				// 临时计算费用
				// search all the agreement & list them	
				resultFee = calculateNewFee(lastFee,room);
			}
	 	}
		return resultFee;
	}
	
	/**
	 * 计算单个房间下一次的待收费用（不管该房间本期是否已经收过租了）
	 * 返回值为什么用List<Room>,是考虑前端展示，未收租费用详情也是这个返回值，保证前端可用一个模板
	 * @param room
	 * @return
	 */
	@Rest(type = "calculate")
	public List<Room> calculateNextFee(int roomid) {
		List<Room> rooms = new ArrayList<Room>();
		Fee resultFee = null;
		Room model = new Room();
		model.setId(roomid);
		Room room = genericService.load(model);
		if (room != null) {
			List<Fee> fees = room.getFees();
			if (fees != null && fees.size() > 0) {
				Fee lastFee = fees.get(fees.size()-1);
				// 附加费
				resultFee = calculateNewFee(lastFee,room);
				room.setReceivableFee(resultFee);
			}
			rooms.add(room);
		}
		return rooms;
	}
	
	/**
	 * 计算一个新的费用，当费用未生成时，可通过该方法进行生成
	 * @param lastFee
	 * @param room
	 * @return
	 */
	private Fee calculateNewFee(Fee lastFee, Room room){
		// 附加费
		List<FeeAddition> feeAdditions = new ArrayList<FeeAddition>();
		
		// 临时计算费用
		// search all the agreement & list them	
		Fee fee = new Fee();
		BigDecimal balance = null;
		if (lastFee != null) {
			
			Agreement agreement = room.getAgreement();
			List<Fee> agreementFees = agreement.getFees();
			balance = lastFee.getBalance();
			if (agreementFees != null && agreementFees.size() > 0) {
				Calendar calendar = Calendar.getInstance();
				String dateStartRecv = "";
				if (agreementFees.size() == 1) {
					dateStartRecv = agreement.getRentBeginDate();
				}else{
					room.setLastFee(lastFee);
					// 这次费用的开始时间 = 上一次费用结束日期的后一天时间作为
					dateStartRecv = DateTimeUtil.getSpecifiedDayAfter(lastFee.getDateEndRecv());;
				}
				fee.setDateBeginRecv(dateStartRecv);
				calendar.setTime(DateTimeUtil.StrToDate(dateStartRecv,DateTimeUtil.DATETIME_FORMAT));
				//rent_cycle=0表示1个月，=1表示2个月   
				calendar.set(Calendar.MONTH,
						calendar.get(Calendar.MONTH) + agreement.getRentCycle() + 1);
				int day = calendar.get(Calendar.DATE);
				calendar.set(Calendar.DATE, day - 1);
				String dateEndRecv = DateTimeUtil.formatDate(calendar.getTime());
				fee.setDateEndRecv(dateEndRecv);
			}
		}
		
		BigDecimal rentCycle = new BigDecimal(1);
		if (room.getAgreement().getRentCycle() != null) {
			int iCycle = room.getAgreement().getRentCycle() + 1 ;
			rentCycle = new BigDecimal(iCycle);
		}
		
		// 租金
		BigDecimal monthRental = new BigDecimal(0);
		if(StringUtils.isNotBlank(room.getRental())){
			monthRental = new BigDecimal(room.getRental());
		}else{
			monthRental = room.getAgreement().getRentPay();
		}
		
		BigDecimal amount = monthRental.multiply(rentCycle);
		BigDecimal rental = amount.add(new BigDecimal(0));
		
		for (FeeRule feeRule : room.getFeeRules()) {
			FeeRuleCfg feeRuleCfg = feeRule.getFeeRuleCfg();
			FeeAddition feeAddition = new FeeAddition();
			//设置额外费用对应的费用规则
			feeAddition.setFeeRuleCfg(feeRuleCfg);
			
			FeeRuleCfgDesc feeRuleCfgDesc = feeRuleCfg.getFeeRuleCfgDesc();
			FeeRuleCfgCalc feeRuleCfgCalc = feeRuleCfg.getFeeRuleCfgCalc();

			if (feeRuleCfgDesc.getType() == FeeRuleType.fixed) { // 固定费用
				
				if (feeRuleCfgDesc.getCalcMode() == FeeRuleCalcMode.normal) {
					feeAddition.setPriceRecv(feeRuleCfgCalc.getPrice());
				} else if (feeRuleCfgDesc.getCalcMode() == FeeRuleCalcMode.areaFactor) {
					BigDecimal price = room.getArea().multiply(feeRuleCfgCalc.getPrice());
					feeAddition.setPriceRecv(price);
				} else {
					feeAddition.setPriceRecv(feeRuleCfgCalc.getPrice());
				}
			} else {	// 水电计算公式
				Meter meter1 = feeRule.getMeter(0);
				Meter meter2 = feeRule.getMeter(1);
				if (meter1 != null && meter2 != null) {
					feeAddition.setMeter1(meter1);
					feeAddition.setMeter2(meter2);
					BigDecimal gap = null;
					
					gap = meter1.getCount().subtract(meter2.getCount());
					
					if (feeRuleCfgDesc.getCalcMode() == FeeRuleCalcMode.threshold) {	// 门限
						if (gap != null && feeRuleCfgCalc.getValueLow() != null 
								&& gap.subtract(feeRuleCfgCalc.getValueLow()).compareTo(BigDecimal.ZERO) < 0) {
							gap = feeRuleCfgCalc.getValueLow();
						}
					}
					
					BigDecimal price = gap.multiply(meter1.getPrice());
					feeAddition.setPriceRecv(price);
				}
				
			}
			if (feeAddition.getPriceRecv() != null) {
				amount = amount.add(feeAddition.getPriceRecv());
			}
			feeAdditions.add(feeAddition);
		}
		
		//计算公摊费用
		if (room.getRoomShareUnits() != null) {
			for (RoomShareUnit roomShareUnit : room.getRoomShareUnits()) {
				ShareUnit shareUnit = roomShareUnit.getShareUnit();
				
				String shareProportion = getShareProportion(roomShareUnit);
				
				String[] proportion = shareProportion.split("/");
				BigDecimal numerrtor = new BigDecimal(proportion[0]);
				BigDecimal denominator = new BigDecimal(proportion[1]);
				
				
				List<FeeRule> feeRules = shareUnit.getFeeRules();
				if (feeRules != null && feeRules.size() > 0) {
					for (FeeRule feeRule : feeRules) {
						FeeRuleCfg feeRuleCfg = feeRule.getFeeRuleCfg();
						FeeAddition feeAddition = new FeeAddition();
						//设置额外费用对应的费用规则
						feeAddition.setFeeRuleCfg(feeRuleCfg);
						FeeRuleCfgDesc feeRuleCfgDesc = feeRuleCfg.getFeeRuleCfgDesc();
						FeeRuleCfgCalc feeRuleCfgCalc = feeRuleCfg.getFeeRuleCfgCalc();
						boolean isShare = feeRuleCfgDesc.getIsShare() == null ? false : feeRuleCfgDesc.getIsShare();
						if (isShare && feeRuleCfgDesc.getType() == FeeRuleType.meter){
							Meter meter1 = feeRule.getMeter(0);
							Meter meter2 = feeRule.getMeter(1);
							if (meter1 != null && meter2 != null) {
								feeAddition.setMeter1(meter1);
								feeAddition.setMeter2(meter2);
								BigDecimal gap = null;
								
								gap = meter1.getCount().subtract(meter2.getCount());
								
								if (feeRuleCfgDesc.getCalcMode() == FeeRuleCalcMode.threshold) {	// 门限
									if (gap.subtract(feeRuleCfgCalc.getValueLow()).compareTo(BigDecimal.ZERO) < 0) {
										gap = feeRuleCfgCalc.getValueLow();
									}
								}
								
								BigDecimal amountPrice = gap.multiply(meter1.getPrice());
								
								BigDecimal price = amountPrice.multiply(numerrtor).divide(denominator, 2, BigDecimal.ROUND_HALF_UP).setScale(2,BigDecimal.ROUND_HALF_UP);
								
								feeAddition.setPriceRecv(price);
								if (numerrtor.intValue() == 0) {
									amountPrice = new BigDecimal(0);
								}
								feeAddition.setShareAmount(amountPrice.setScale(2,BigDecimal.ROUND_HALF_UP));
							}
						}
						if (feeAddition.getPriceRecv() != null) {
							amount = amount.add(feeAddition.getPriceRecv());
						}
						feeAdditions.add(feeAddition);
					}
				}
			}
		}
		
		fee.setRental(rental);
		fee.setFeeAdditions(feeAdditions);
		// 应收应该合并余额
		if (balance != null) {
			amount = amount.subtract(balance);
		}
		fee.setAmountRecv(amount);
		return fee;
	}
	
	/**
	 * 获取公摊占比,如1/3
	 * @param roomShareUnit
	 * @return
	 */
	private String getShareProportion(RoomShareUnit roomShareUnit){
		String result = "0/1";
		Room masterRoom = roomShareUnit.getRoom();
		List<Fee> selfFees = masterRoom.getAgreement().getFees();
		BigDecimal totalDays = new BigDecimal(0);
		if (selfFees.size() > 1) {
			Fee selfFee = selfFees.get(0);
			BigDecimal ownIntervalDays = new BigDecimal(DateTimeUtil.getIntervalDays(selfFee.getDateBeginRecv(), selfFee.getDateEndRecv()));
			ShareUnit shareUnit = roomShareUnit.getShareUnit();
			List<RoomShareUnit> roomShareUnits = shareUnit.getRoomShareUnits();
			if (roomShareUnits != null && roomShareUnits.size() > 0) {
				for (RoomShareUnit tempRoomShareUnit : roomShareUnits) {
					Room room = tempRoomShareUnit.getRoom();
					ValidAgreement agreement = room.getAgreement();
					if (agreement != null) {
						List<Fee> fees = agreement.getFees();
						if (fees.size() > 1) {
							Fee compareFee = fees.get(0);
							String strSelfDateEndRecv = DateTimeUtil.formatStringDate(selfFee.getDateEndRecv(), DateTimeUtil.ISO_DATE_FORMAT);
							for (Fee fee : fees) {
								// 找统一收费结束时间的费用记录
								String strCompareDateEndRecv = DateTimeUtil.formatStringDate(fee.getDateEndRecv(), DateTimeUtil.ISO_DATE_FORMAT);
								if (strSelfDateEndRecv.equals(strCompareDateEndRecv)) {
									compareFee = fee;
								}
							}
							BigDecimal intervalDays = new BigDecimal(DateTimeUtil.getIntervalDays(compareFee.getDateBeginRecv(), compareFee.getDateEndRecv()));
							totalDays = totalDays.add(intervalDays);
						}
					}
				}
			}
			if (totalDays.intValue() != 0) {
				result = ownIntervalDays + "/" + totalDays;
			}
		}
		
		return result;
	}
	
	public void copyFee2FeeRecord(Fee fee, FeeRecord feeRecord){
		ModelUtil.copy(fee, feeRecord, true);
		List<FeeAddition> feeAdditions = fee.getFeeAdditions();
		List<FeeAdditionRecord> feeAdditionRecords = new ArrayList<FeeAdditionRecord>();
		if (feeAdditions != null && feeAdditions.size() > 0) {
			for (FeeAddition feeAddition : feeAdditions) {
				feeAddition.setId(null);
				FeeAdditionRecord feeAdditionRecord = new FeeAdditionRecord();
				ModelUtil.copy(feeAddition, feeAdditionRecord, true);
				feeAdditionRecords.add(feeAdditionRecord);
			}
			feeRecord.setFeeAdditionRecords(feeAdditionRecords);
		}
	}
	
	public void copyFeeRecord2Fee(FeeRecord feeRecord, Fee fee){
		ModelUtil.copy(feeRecord, fee, true);
		List<FeeAdditionRecord> feeAdditionRecords = feeRecord.getFeeAdditionRecords();
		List<FeeAddition> feeAdditions = new ArrayList<FeeAddition>();
		if (feeAdditionRecords != null && feeAdditionRecords.size() > 0) {
			for (FeeAdditionRecord feeAdditionRecord : feeAdditionRecords) {
				//feeAdditionRecord.setId(null);
				FeeAddition feeAddition = new FeeAddition();
				ModelUtil.copy(feeAdditionRecord, feeAddition, true);
				//feeAddition.setId(null);
				feeAdditions.add(feeAddition);
			}
			fee.setFeeAdditions(feeAdditions);
		}
	}
	
	/**
	 * 修复待收费的总额问题
	 */
	public void repairedFeeRecordAmountRecv() {
		QLInfo qlInfo = new QLInfo("select a from " + FeeRecord.class.getName() + " a where a.status = ? and a.dateActual is null and not exists (select b.id from " + RentalOrder.class.getName() + " b where b.feeRecord.id = a.id)", true);
		qlInfo.addParam(FeeRecord.FEE_STATUS_RENT_TODO);
		/*qlInfo.addParam(RentalOrder.ORDER_STATE_WAITING_PAYMENT);*/
		int count = genericService.getCount(qlInfo, false);
		for (int i = 0; i < count; i+= 1000) {
			qlInfo.setFirstResult(i);
			qlInfo.setMaxResults(1000);
			List<FeeRecord> feeRecords = genericService.searchByQl(qlInfo).getData();
			for (FeeRecord feeRecord : feeRecords) {
				if (feeRecord.getFeeAdditionRecords() != null) {
					BigDecimal amountRecv = feeRecord.getRental();
					for (FeeAdditionRecord feeAdditionRecord : feeRecord.getFeeAdditionRecords()) {
						amountRecv = amountRecv.add(feeAdditionRecord.getPriceRecv());
					}
					if (feeRecord.getAgreement() != null) {
						QLInfo qlInfo2 = new QLInfo("select a from " + Fee.class.getName() + " a where a.agreement = ? order by a.id desc", true);
						qlInfo2.addParam(feeRecord.getAgreement());
						qlInfo2.setFirstResult(0);
						qlInfo2.setMaxResults(1);
						Fee fee = (Fee) genericService.searchByQl(qlInfo2).getData(0);
						if (fee != null && fee.getBalance() != null) {
							amountRecv = amountRecv.add(fee.getBalance().multiply(BigDecimal.valueOf(-1)));
						}
					}
					if (feeRecord.getAmountRecv().compareTo(amountRecv) != 0) {
						logger.info("修复FeeRecord的amountRecv，修复前：" + feeRecord.getAmountRecv() + "，修复后：" + amountRecv);
						feeRecord.setAmountRecv(amountRecv);
						genericService.merge(feeRecord);
					}
				}
			}
		}
	}
	
	/**
	 * 修改收费项的单价后，对已经产生的收费进行更新。
	 * @param dbFeeRuleCfg
	 * @param oldPrice
	 * @param newPrice
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Transactional
	public boolean repaireFeeRecordWhenFeeRuleCfgPriceChanged(FeeRuleCfg feeRuleCfg, BigDecimal newPrice) {
		FeeRuleCfg dbFeeRuleCfg = genericService.load(feeRuleCfg);
		BigDecimal oldPrice = dbFeeRuleCfg.getFeeRuleCfgCalc().getPrice();
		QLInfo qlInfo = new QLInfo("select a from " + FeeAdditionRecord.class.getName() + " a where a.feeRuleCfg = ? and a.feeRecord.status = ?", false, dbFeeRuleCfg, FeeRecord.FEE_STATUS_RENT_TODO);
		List<FeeAdditionRecord> dbFeeAdditionRecords = genericService.searchByQl(qlInfo).getData();
		for (FeeAdditionRecord feeAdditionRecord : dbFeeAdditionRecords) {
			if (feeAdditionRecord.getStatus().equals(FeeAdditionRecord.STATUS_NEED_CONFIRM)) {
				feeAdditionRecord.setPriceRecv(feeAdditionRecord.getPriceRecv().multiply(newPrice).divide(oldPrice, 2, RoundingMode.HALF_UP));
				em.merge(feeAdditionRecord);
			} else {
				FeeRecord feeRecord = feeAdditionRecord.getFeeRecord();
				RentalOrder dbRentalOrder = rentalOrderService.searchRentalOrderByFeeRecord(feeRecord);
				if (dbRentalOrder == null) {
					BigDecimal newTotalPrice = feeAdditionRecord.getPriceRecv().multiply(newPrice).divide(oldPrice, 2, RoundingMode.HALF_UP);
					BigDecimal needAddPrice = newTotalPrice.subtract(feeAdditionRecord.getPriceRecv());
					feeAdditionRecord.setPriceRecv(newTotalPrice);
					feeRecord.setAmountRecv(feeRecord.getAmountRecv().add(needAddPrice));
					em.merge(feeRecord);
				} else {
					feeAdditionRecord.setPriceRecv(feeAdditionRecord.getPriceRecv().multiply(newPrice).divide(oldPrice, 2, RoundingMode.HALF_UP));
					em.merge(feeAdditionRecord);
				}
			}
		}
		return true;
	}
}